package com.liu.concurrent.sync;


/**
 * 生产者消费者
 * 方案一：使用Synchronized
 * 循环等待
 * 业务
 * 唤醒
 * @author liubo
 */
public class ProducerConsumerBySynchronized {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}

class Data{
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        //STEP1 循环等待
        //不能使用if判断，会导致虚假唤醒，需要使用while循环
//        if (number!=0) {
//            this.wait();
//        }
        while (number!=0) {
            this.wait();
        }

        //STEP2 业务
        number++;
        System.out.println(Thread.currentThread().getName()+number);

        //STEP3 通知
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        //STEP1 循环等待
        while (number==0) {
            this.wait();
        }

        //STEP2 业务
        number--;
        System.out.println(Thread.currentThread().getName()+number);

        //STEP3 通知
        this.notifyAll();
    }
}

